package com.ggjj.rankinglistdemo.controller;

import com.ggjj.rankinglistdemo.dto.UserPointReq;
import com.ggjj.rankinglistdemo.dto.UserRanking;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@RestController
public class UserRankingController {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 批量将用户积分数据写入到redis的zset中
     * @param userPointsReqList
     * @return
     */
    @PostMapping("/addUserPoint")
    public boolean addUserPoint(@RequestBody List<UserPointReq> userPointsReqList){
        String key = "user:ranking";
        for (UserPointReq userPointReq : userPointsReqList) {
            String userId = userPointReq.getUserId();
            Integer points = userPointReq.getPoints();
            Long updateTime = userPointReq.getUpdateTime();
            //先按照积分降序（从大到小），积分相同时按照最后更新时间升序（从小到大）
            //因为存入redis的score先是按照积分从大到小排，例如150>100 150排第一，
            //但是时间戳按从小到大排例如222<333 当积分相同时，时间戳越小排名越前，但是违背了score倒序。所以用1-
            double score = points + (1 - updateTime / 1e13);
            stringRedisTemplate.opsForZSet().add(key, userId, score);
        }
        return true;
    }

    /**
     * 查询用户积分排行榜前多少名
     * @param topN
     * @return
     */
    @GetMapping("/getUserRankings")
    public List<UserRanking> getUserRankings(@RequestParam("topN") Integer topN){
        String key = "user:ranking";

        Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().reverseRangeWithScores(key, 0, topN - 1);

        List<UserRanking> userRankingList = new ArrayList<>();

        for (ZSetOperations.TypedTuple<String>typedTuple : typedTuples) {
            UserRanking userRanking = new UserRanking();
            userRanking.setUserId(typedTuple.getValue());
            userRanking.setRedisScore(typedTuple.getScore());
            userRankingList.add(userRanking);
        }
        return userRankingList;
    }
}
